  /*
>  * INSANE - Interactive Structural Analysis Environment
>  *
>  * Copyright (C) 2003-2004
>  * Universidade Federal de Minas Gerais
>  * Escola de Engenharia
>  * Departamento de Engenharia de Estruturas
>  *
>  * Author's email :     insane@dees.ufmg.br
>  * Author's Website :   http://www.dees.ufmg.br/insane
>  *
>  * This program is free software; you can redistribute it and/or
>  * modify it under the terms of the GNU General Public License
>  * as published by the Free Software Foundation; either version 2
>  * of the License, or any later version.
>  *
>  * This program is distributed in the hope that it will be useful,
>  * but WITHOUT ANY WARRANTY; without even the implied warranty of
>  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>  * GNU General Public License for more details.
>  *
>  * You should have received a copy of the GNU General Public License
>  * along with this program; if not, write to the Free Software
>  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-
> 1307, USA.
 *
 */
package br.ufmg.dees.insane.ui.rich.postp.postp_view;

import java.text.NumberFormat;
import java.util.LinkedList;
import java.util.Locale;

import br.ufmg.dees.insane.util.IPoint3d;

/**
 * 
 * @author Penna, S.S. Pitangueira, Roque
 * @since 28/10/2006
 */
public class ContourCalculator {

    private int numContoursColors;
    private LinkedList contoursColors;
    private LinkedList respLimits;
    private LinkedList<Contour> contoursMap;
    private IPoint3d firstVertex;
    private double firstResp;
    private int firstLevelA;
    private int firstLevelB;
    private IPoint3d prevVertex;
    private double prevResp;
    private int prevLevelA;
    private int prevLevelB;
    private boolean first = true;
    private String keyValue = "Mxx";
    private static int digits = 6;
    
    public ContourCalculator(LinkedList colors, double vMax,double vMin){
        this.contoursColors = colors;
        this.numContoursColors = this.contoursColors.size();
        this.respLimits = new LinkedList();
        this.respLimits = this.initLimits(vMax, vMin);
        this.contoursMap = new LinkedList<Contour>();
        this.initContourMap();
    }
    
    private LinkedList initLimits(double vMax, double vMin){
    	
    	NumberFormat f; 
        f = (NumberFormat)NumberFormat.getNumberInstance(Locale.UK);
        f.setGroupingUsed(false);
        f.setMaximumFractionDigits(digits);
        
        vMax = new Double(f.format(vMax));
    	vMin = new Double(f.format(vMin));
    	
        double delta = (vMax-vMin)/(this.numContoursColors-1); 
        LinkedList<Double> contourLimits = new LinkedList<Double>();
        contourLimits.add(vMin);
        for (int i = 1; i < this.numContoursColors-1; i++) {
            double aux = ((Double)contourLimits.get(i-1))+delta;
            contourLimits.add(aux);
        }
        contourLimits.add(vMax);
        return contourLimits;
    }
    
    private void initContourMap(){
        for (int i = 0; i < this.numContoursColors+2; i++) {
            this.contoursMap.add(new Contour(i));
        }
    }
    
    private int[] classify(double resp){
    	
        int level = 0;
        int levelA = 0;
        int levelB = 0;
        
        while(level<(this.numContoursColors+1) && resp>((Double)this.respLimits.get(level))){
            level++;
        }
       
        levelB = level;
        if(level==(this.numContoursColors+1)){
            levelA = level;
        }else if(resp==((Double)this.respLimits.get(level))){
            levelA = level+1;
        }else{
            levelA = level;
        }
        
        int[] levelsAB = new int[2];
        levelsAB[0] = levelA;
        levelsAB[1] = levelB;
        
        return levelsAB;
    }
    
    private void insert(int level, IPoint3d v){
        for (int i = 0; i < this.contoursMap.size(); i++) {
            Contour c = (Contour)this.contoursMap.get(i);
            if(c.getLevel()==level){
                c.getContoursVertices().add(v);
            }else{
                continue;
            }
        }
    }
    
    private IPoint3d interpolate(double resp,IPoint3d v,double respLimit){
        double aux = (respLimit-this.prevResp)/(resp-this.prevResp);
        double xLimit = aux*(v.x-this.prevVertex.x)+this.prevVertex.x;
        double yLimit = aux*(v.y-this.prevVertex.y)+this.prevVertex.y;
        double zLimit = aux*(v.z-this.prevVertex.z)+this.prevVertex.z;
        return new IPoint3d(xLimit,yLimit,zLimit);
    }
    
    private void addEdge(int levelA, int levelB, IPoint3d v, double resp){
        if(levelA>this.prevLevelB){
            if(levelB>this.prevLevelA){
               this.prevVertex = interpolate(resp,v,(Double)this.respLimits.get(this.prevLevelA));
               insert(this.prevLevelA,this.prevVertex);
               insert(this.prevLevelA+1,this.prevVertex);
               this.prevResp = (Double)this.respLimits.get(this.prevLevelA);
               this.prevLevelB = this.prevLevelA;
               this.prevLevelA = this.prevLevelA + 1;
               addEdge(levelA,levelB,v,resp);
            }
        }else if(this.prevLevelB>levelA){
            this.prevVertex = interpolate(resp,v,(Double)this.respLimits.get(this.prevLevelB-1));
            insert(this.prevLevelB-1,this.prevVertex);
            insert(this.prevLevelB,this.prevVertex);
            this.prevResp = (Double)this.respLimits.get(this.prevLevelB-1);
            this.prevLevelA = this.prevLevelB;
            this.prevLevelB = this.prevLevelB-1;
            addEdge(levelA,levelB,v,resp);
        }
    }
    
    public void addVertex(IPoint3d v, double resp){
    	
    	NumberFormat f; 
        f = (NumberFormat)NumberFormat.getNumberInstance(Locale.UK);
        f.setGroupingUsed(false);
        f.setMaximumFractionDigits(digits);
        resp = new Double(f.format(resp));
    	
        int levelA, levelB;
        if(this.numContoursColors<1){
            return;
        }
        int[] aux = classify(resp);
        levelA = aux[0];
        levelB = aux[1];
        
        if(first){
            first = false;
            this.firstVertex = v;
            this.firstResp = resp;
            this.firstLevelA = levelA;
            this.firstLevelB = levelB;
        }else{
            addEdge(levelA, levelB,v, resp);
        }
        insert(levelA, v);
        if(levelA!=levelB){
            insert(levelB,v);
        }
        this.prevVertex = v;
        this.prevResp = resp;
        this.prevLevelA = levelA;
        this.prevLevelB = levelB;
    }

    
    public void end(){
        addEdge(this.firstLevelA,this.firstLevelB,this.firstVertex,this.firstResp);
    }
    
    
    public LinkedList getContoursColors() {
        return contoursColors;
    }

    public void setContoursColors(LinkedList contoursColors) {
        this.contoursColors = contoursColors;
    }

    public LinkedList getContoursMap() {
        return contoursMap;
    }

    public void setContoursMap(LinkedList<Contour> contoursMap) {
        this.contoursMap = contoursMap;
    }

    public String getKeyValue() {
        return keyValue;
    }

    public void setKeyValue(String keyValue) {
        this.keyValue = keyValue;
    }

    public LinkedList getRespLimits() {
        return respLimits;
    }

    public void setRespLimits(LinkedList respLimits) {
        this.respLimits = respLimits;
    }

	public static int getDigits() {
		return digits;
	}

	public static void setDigits(int digitsN) {
		digits = digitsN;
	}
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
//**********************************************************************************************    
}//end of this class


